package com.wk.repeaters;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 仿对象（mock object）：人工干预{@link Repeater}的行为，控制什么时候执行任务<br>
 * 用途：在测试环境下替代并模仿其他{@link Repeater}的行为，以将被执行的任务和执行策略（通常和时间有关）解耦，以创建自动化测试用例<br>
 * 例：替代{@link FixedIntervalRepeater}，将被执行的任务和时间解耦，不必等待即可立刻执行任务并断言（assert）其执行结果
 * 
 * @author Bai Yu
 *
 */
public class ManualRepeater implements Repeater {
	public ManualRepeater(){
		executionToken = new LinkedBlockingQueue<>();
	}
	
	@Override
	public void schedule(Runnable task) {
		this.task = task;
	}

	@Override
	public void start() {
		executionToken.clear();
		new Thread(new ExecuteTask()).start();
	}

	/**
	 * 手动驱动执行一次任务<br>
	 * 每次调用将导致执行一次任务；各次任务依次执行而非同时执行
	 */
	public void execute() {
		executionToken.add(EXECUTE_ONCE);
	}

	@Override
	public void cancel() {
		executionToken.add(CANCEL);
	}

	private Runnable task;

	// 当需要执行任务或停止执行时，在该容器里放入令牌（token）
	BlockingQueue<Integer> executionToken;
	private static final int EXECUTE_ONCE = 1;
	private static final int CANCEL = -1;

	private class ExecuteTask implements Runnable {
		@Override
		public void run() {
			boolean running = true;
			while (running) {
				try {
					int token = executionToken.take();
					switch (token) {
					case EXECUTE_ONCE:
						task.run();
						break;
					case CANCEL:
						running = false;
						break;
					}
				} catch (InterruptedException e) {
					running = false;
				}
			}
		}
	}
}
